"""
同步任务实现
"""

import asyncio
from datetime import datetime
from typing import Dict, Any, Optional, List

from celery import current_task
from sqlalchemy.ext.asyncio import AsyncSession

from .celery import celery
from database import AsyncSessionLocal
from models.execution import Execution
from models.task import Task
from models.repository import Repository
from models.log import Log
from services.git_service import git_service
from utils.logger import get_logger

logger = get_logger(__name__)


def get_db_session() -> AsyncSession:
    """获取数据库会话"""
    return AsyncSessionLocal()


async def log_execution_step(
    execution_id: int,
    level: str,
    message: str,
    step: Optional[str] = None,
    details: Optional[Dict[str, Any]] = None,
    repo_id: Optional[int] = None
) -> None:
    """记录执行步骤日志"""
    async with get_db_session() as db:
        log_entry = Log(
            execution_id=execution_id,
            level=level,
            message=message,
            step=step,
            details=details,
            repo_id=repo_id
        )
        db.add(log_entry)
        await db.commit()


@celery.task(bind=True, max_retries=3)
def execute_git_sync(self, execution_id: int) -> Dict[str, Any]:
    """
    执行Git同步任务

    Args:
        execution_id: 执行记录ID

    Returns:
        执行结果
    """
    task_id = current_task.request.id

    logger.info("开始执行Git同步任务", execution_id=execution_id, task_id=task_id)

    try:
        # 运行异步任务
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        try:
            result = loop.run_until_complete(_execute_git_sync_async(execution_id))
            return result
        finally:
            loop.close()

    except Exception as e:
        logger.error("Git同步任务执行失败", execution_id=execution_id, error=str(e))

        # 记录错误日志
        try:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(
                log_execution_step(
                    execution_id=execution_id,
                    level="error",
                    message=f"同步任务失败: {str(e)}",
                    step="error",
                    details={"error": str(e), "exception": type(e).__name__}
                )
            )
            loop.close()
        except Exception:
            pass

        # 更新执行状态为失败
        try:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
            loop.run_until_complete(_update_execution_status(execution_id, "failure", str(e)))
            loop.close()
        except Exception:
            pass

        raise


async def _execute_git_sync_async(execution_id: int) -> Dict[str, Any]:
    """异步执行Git同步任务"""
    async with get_db_session() as db:
        # 获取执行记录
        execution = await db.get(Execution, execution_id)
        if not execution:
            raise ValueError(f"执行记录不存在: {execution_id}")

        # 获取任务信息
        task = await db.get(Task, execution.task_id)
        if not task:
            raise ValueError(f"任务不存在: {execution.task_id}")

        # 更新执行状态为运行中
        execution.status = "running"
        execution.start_time = datetime.utcnow()
        await db.commit()

        await log_execution_step(
            execution_id=execution_id,
            level="info",
            message="开始执行同步任务",
            step="init"
        )

        try:
            # 1. 克隆源代码库
            await log_execution_step(
                execution_id=execution_id,
                level="info",
                message="克隆源代码库",
                step="clone"
            )

            source_repo = await db.get(Repository, task.source_repo_id)
            if not source_repo:
                raise ValueError("源代码库不存在")

            source_repo_dir = await git_service.clone_repository(source_repo)

            # 2. 拉取最新代码
            source_branch = task.branch_mapping.get("source_branch", "main")
            await log_execution_step(
                execution_id=execution_id,
                level="info",
                message=f"拉取源代码库最新代码 (分支: {source_branch})",
                step="pull"
            )

            source_commit = await git_service.pull_changes(source_repo_dir, source_branch)
            execution.source_commit = source_commit

            # 3. 添加额外文件（如果有）
            if task.files:
                await log_execution_step(
                    execution_id=execution_id,
                    level="info",
                    message=f"添加额外文件 ({len(task.files)} 个文件)",
                    step="add_files"
                )
                # TODO: 实现文件添加逻辑
                # files_to_add = await get_task_files(db, task.files)
                # await git_service.add_files(source_repo_dir, files_to_add)

            # 4. 并推送到目标代码库
            target_results = []
            for target_repo_info in task.target_repos:
                target_repo_id = target_repo_info.get("id")
                if not target_repo_id:
                    continue

                target_repo = await db.get(Repository, target_repo_id)
                if not target_repo:
                    await log_execution_step(
                        execution_id=execution_id,
                        level="warning",
                        message=f"目标代码库不存在: {target_repo_id}",
                        step="push",
                        repo_id=target_repo_id
                    )
                    continue

                target_branch = task.get_branch_mapping(target_repo_id)
                if not target_branch:
                    target_branch = source_branch

                await log_execution_step(
                    execution_id=execution_id,
                    level="info",
                    message=f"推送到目标代码库 (分支: {target_branch})",
                    step="push",
                    repo_id=target_repo_id
                )

                try:
                    pushed_commit = await git_service.push_to_target(
                        source_repo_dir,
                        target_repo,
                        target_branch,
                        task.force_push
                    )

                    target_result = {
                        "repo_id": target_repo_id,
                        "repo_name": target_repo.name,
                        "status": "success",
                        "commit": pushed_commit,
                        "branch": target_branch,
                        "message": "推送成功"
                    }

                    await log_execution_step(
                        execution_id=execution_id,
                        level="info",
                        message=f"推送到目标代码库成功",
                        step="push",
                        repo_id=target_repo_id,
                        details={"commit": pushed_commit, "branch": target_branch}
                    )

                except Exception as e:
                    target_result = {
                        "repo_id": target_repo_id,
                        "repo_name": target_repo.name,
                        "status": "failure",
                        "commit": None,
                        "branch": target_branch,
                        "message": f"推送失败: {str(e)}"
                    }

                    await log_execution_step(
                        execution_id=execution_id,
                        level="error",
                        message=f"推送到目标代码库失败: {str(e)}",
                        step="push",
                        repo_id=target_repo_id,
                        details={"error": str(e)}
                    )

                target_results.append(target_result)

            execution.target_results = target_results

            # 5. 验证同步结果
            verification_results = []
            for target_result in target_results:
                if target_result["status"] == "success":
                    # TODO: 实现验证逻辑
                    verification_result = {
                        "repo_id": target_result["repo_id"],
                        "repo_name": target_result["repo_name"],
                        "commit_check": {
                            "status": "success",
                            "expected": target_result["commit"],
                            "actual": target_result["commit"]
                        },
                        "file_check": {
                            "status": "success",
                            "files_checked": 0,
                            "files_passed": 0
                        }
                    }
                else:
                    verification_result = {
                        "repo_id": target_result["repo_id"],
                        "repo_name": target_result["repo_name"],
                        "commit_check": {"status": "skipped"},
                        "file_check": {"status": "skipped"}
                    }

                verification_results.append(verification_result)

            execution.verification_results = verification_results

            # 6. 更新执行状态
            end_time = datetime.utcnow()
            execution.end_time = end_time
            execution.duration = int((end_time - execution.start_time).total_seconds())

            # 判断整体执行状态
            failed_count = sum(1 for result in target_results if result["status"] == "failure")
            if failed_count == 0:
                execution.status = "success"
                message = "同步任务执行成功"
            else:
                execution.status = "failure"
                message = f"同步任务部分失败 ({failed_count}/{len(target_results)} 个目标仓库失败)"

            await db.commit()

            await log_execution_step(
                execution_id=execution_id,
                level="info" if execution.status == "success" else "error",
                message=message,
                step="complete",
                details={
                    "duration": execution.duration,
                    "successful_targets": len(target_results) - failed_count,
                    "failed_targets": failed_count
                }
            )

            logger.info(
                "Git同步任务执行完成",
                execution_id=execution_id,
                status=execution.status,
                duration=execution.duration
            )

            return {
                "execution_id": execution_id,
                "status": execution.status,
                "duration": execution.duration,
                "target_results": target_results,
                "verification_results": verification_results
            }

        except Exception as e:
            # 更新执行状态为失败
            execution.status = "failure"
            execution.error_message = str(e)
            execution.end_time = datetime.utcnow()
            if execution.start_time:
                execution.duration = int((execution.end_time - execution.start_time).total_seconds())

            await db.commit()

            await log_execution_step(
                execution_id=execution_id,
                level="error",
                message=f"同步任务执行失败: {str(e)}",
                step="error",
                details={"error": str(e), "exception": type(e).__name__}
            )

            raise


async def _update_execution_status(
    execution_id: int,
    status: str,
    error_message: Optional[str] = None
) -> None:
    """更新执行状态"""
    async with get_db_session() as db:
        execution = await db.get(Execution, execution_id)
        if execution:
            execution.status = status
            if error_message:
                execution.error_message = error_message
            execution.end_time = datetime.utcnow()
            if execution.start_time:
                execution.duration = int((execution.end_time - execution.start_time).total_seconds())
            await db.commit()


@celery.task
def cleanup_old_logs():
    """清理过期日志"""
    try:
        logger.info("开始清理过期日志")

        # TODO: 实现日志清理逻辑

        logger.info("过期日志清理完成")
        return {"status": "success", "message": "日志清理完成"}

    except Exception as e:
        logger.error("日志清理失败", error=str(e))
        return {"status": "failure", "error": str(e)}


@celery.task
def health_check():
    """健康检查任务"""
    try:
        # 检查数据库连接
        async with get_db_session() as db:
            await db.execute("SELECT 1")

        # 检查Git服务
        # TODO: 添加更多健康检查

        return {
            "status": "healthy",
            "timestamp": datetime.utcnow().isoformat(),
            "checks": {
                "database": "ok",
                "git_service": "ok"
            }
        }

    except Exception as e:
        logger.error("健康检查失败", error=str(e))
        return {
            "status": "unhealthy",
            "timestamp": datetime.utcnow().isoformat(),
            "error": str(e)
        }